/**
 * PositionHelper.java
 */
package com.phonemap.helper;

import static com.google.appengine.api.utils.SystemProperty.environment;
import static com.google.appengine.api.utils.SystemProperty.Environment.Value.Development;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.GeoPt;
import com.google.appengine.api.search.Document;
import com.google.appengine.api.search.Field;
import com.google.appengine.api.search.GeoPoint;
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
import com.google.appengine.api.search.Query;
import com.google.appengine.api.search.QueryOptions;
import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.ScoredDocument;
import com.google.appengine.api.search.SearchServiceFactory;
import com.google.appengine.api.search.SortExpression;
import com.google.appengine.api.search.SortOptions;
import com.phonemap.common.AppConstant;
import com.phonemap.dto.PositionDTO;
import com.phonemap.models.Position;
import com.phonemap.search.SearchIndexManager;

/**
 * The Class PositionHelper.
 *
 * @author Phu
 */
public final class PositionHelper {
	
	/** The Constant log. */
	private static Logger logger = Logger.getLogger(PositionHelper.class
			.getName());
	
	/**
	 * Gets the index.
	 *
	 * @return the index
	 */
	public static Index getIndex() {
		IndexSpec indexSpec = IndexSpec.newBuilder().setName(AppConstant.ENTITY_POSITION)
				.build();
		return SearchServiceFactory.getSearchService().getIndex(indexSpec);
	}
	
	/**
	 * Instantiates a new position helper.
	 */
	private PositionHelper() {
		
	}
	
	
	/**
	 * Builds the document.
	 *
	 * @param positionId the position id
	 * @param userId the user id
	 * @param located the located
	 * @param locatedTime the located time
	 * @return the document
	 */
	public static Document buildDocument(final long positionId,
			final long userId, final GeoPt located, final Date locatedTime) {
		logger.info("Build Position index");
		GeoPoint geoPoint = new GeoPoint(located.getLatitude(), located.getLongitude());
		Document.Builder builder = Document
				.newBuilder()
				.addField(
						Field.newBuilder().setName(Position.POSITION_ID_FIELD)
						.setText(Long.toString(positionId)))
				.addField(
						Field.newBuilder().setName(Position.USER_ID_FIELD)
								.setText(Long.toString(userId)))
				.addField(
						Field.newBuilder().setName(Position.LOCATED_FIELD)
								.setGeoPoint(geoPoint))
				.addField(
						Field.newBuilder().setName(Position.LOCATED_TIME_FIELD)
								.setDate(locatedTime));

		// geo-location doesn't work under dev_server, so let's add another
		// field to use for retrieving documents
		if (environment.value() == Development) {
			builder.addField(Field.newBuilder().setName("value").setNumber(1));
		}

		Document place = builder.build();

		return place;
	}
	
	/**
	 * Gets the history.
	 *
	 * @param userId the user id
	 * @param daysAgo the days ago
	 * @param offset the offset
	 * @return the history
	 */
	public static List<PositionDTO> getHistory(final long userId,
			final int daysAgo, final int offset) {
		//FIXME time zone based on locale
		
		logger.info("Getting history..");
		
		Date date = new Date();
		long time = date.getTime() - daysAgo * AppConstant.ONE_DAY_MILLISECOND;
		date.setTime(time);
		
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		
		// Build the SortOptions with 2 sort keys
		SortOptions sortOptions = SortOptions
				.newBuilder()
				.addSortExpression(
						SortExpression
								.newBuilder()
								.setExpression(Position.LOCATED_TIME_FIELD)
								.setDirection(
										SortExpression.SortDirection.DESCENDING)
								.setDefaultValueDate(date))
				.setLimit(AppConstant.LIMIT_NUM).build();

	    // Build the QueryOptions
		QueryOptions options = QueryOptions
				.newBuilder()
				.setOffset(offset * AppConstant.MAX_PAGING)
				.setLimit(AppConstant.MAX_PAGING)
				.setFieldsToReturn(Position.POSITION_ID_FIELD, Position.USER_ID_FIELD,
						Position.LOCATED_FIELD, Position.LOCATED_TIME_FIELD)
				.setSortOptions(sortOptions).build();
		
		// A query string
		String queryString = Position.USER_ID_FIELD + AppConstant.EQUAL + userId;
		queryString += AppConstant.SPACE_STRING + AppConstant.AND_STRING + AppConstant.SPACE_STRING;
		queryString += Position.LOCATED_TIME_FIELD + AppConstant.GREATER_THAN + dateFormat.format(date);
		
		 //  Build the Query and run the search
	//  Build the Query and run the search
	    Query query = Query.newBuilder().setOptions(options).build(queryString);

		Results<ScoredDocument> results = getIndex().search(query);
		
		List<PositionDTO> positions = new ArrayList<PositionDTO>();
		PositionDTO dto = null;
		
		for (ScoredDocument document : results) {
			dto = new PositionDTO();
			dto.setPositionId(Long.parseLong(document.getOnlyField(Position.POSITION_ID_FIELD).getText()));
			dto.setUserId(Long.parseLong(document.getOnlyField(Position.USER_ID_FIELD).getText()));
			GeoPoint geoPoint = document.getOnlyField(Position.LOCATED_FIELD).getGeoPoint();
			dto.setLocated(geoPoint);
			dto.setLocatedTime(document.getOnlyField(Position.LOCATED_TIME_FIELD).getDate());
			
			positions.add(dto);
		}

		return positions;
	}
	
	/**
	 * Delete old index.
	 *
	 * @param positionId the position id
	 */
	public static void deleteOldIndex(final long positionId) {
		Index index = getIndex();
		Results<ScoredDocument> documents = SearchIndexManager.INSTANCE
				.retrieveDocuments(index, Long.toString(positionId));
		for (ScoredDocument scoredDocument : documents) {
			SearchIndexManager.INSTANCE.deleteDocumentFromIndex(scoredDocument
					.getId());
		}
	}

}
